package com.rc.web.runner;

import com.rc.common.annotate.WithoutTenant;
import com.rc.common.util.JsonUtil;
import com.rc.pojo.po.Activity;
import com.rc.pojo.po.Adoption;
import com.rc.pojo.po.Farm;
import com.rc.pojo.po.SearchDoc;
import com.rc.web.converter.SearchConverter;
import com.rc.web.service.ActivityService;
import com.rc.web.service.AdoptionService;
import com.rc.web.service.FarmService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 搜索初始化运行器
 * 用于在应用启动时初始化Elasticsearch数据
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class SearchRunner implements ApplicationRunner {
    private final RestHighLevelClient client;
    private final FarmService farmService;
    private final AdoptionService adoptionService;
    private final ActivityService activityService;
    private final SearchConverter searchConverter;

    /**
     * 异步执行初始化任务
     * @param args 应用启动参数
     */
    @Async
    @WithoutTenant
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("初始化es =================》");
//        init();
        log.info("初始化es结束 =================》");
    }

    /**
     * 初始化Elasticsearch数据
     */
    public void init() throws Exception {
        // 创建批量请求
        BulkRequest request = new BulkRequest("items");

        // 初始化搜索文档列表
        List<SearchDoc> searchDocList = new ArrayList<>();

        // 获取农场列表并转换为Map
        List<Farm> farmList = farmService.list();
        Map<Long, Farm> farmMap = farmList.stream()
                .collect(Collectors.toMap(Farm::getId, farm -> farm));

        // 初始化农场、领养、活动数据
        initFarm(farmList, searchDocList);
        initAdoption(farmMap, searchDocList);
        initActivity(farmMap, searchDocList);

        // 将搜索文档转换为JSON并添加到批量请求中
        searchDocList.forEach(searchDoc -> {
            String jsonDoc = JsonUtil.toJson(searchDoc);
            String id = String.format("%s%s", searchDoc.getItemId(), searchDoc.getType());
            IndexRequest indexRequest = new IndexRequest()
                    .id(id)
                    .source(jsonDoc,XContentType.JSON);
            request.add(indexRequest);
        });

        // 执行批量请求
        client.bulk(request, RequestOptions.DEFAULT);
    }

    /**
     * 初始化活动数据
     * @param farmMap 农场Map
     * @param searchDocList 搜索文档列表
     */
    private void initActivity(Map<Long, Farm> farmMap, List<SearchDoc> searchDocList) {
        List<SearchDoc> docList = activityService.list()
                .stream()
                .map(searchConverter::toDoc)
                .filter(searchDoc -> extracted(searchDoc, farmMap))
                .toList();
        searchDocList.addAll(docList);
    }

    /**
     * 初始化农场数据
     * @param farmList 农场列表
     * @param searchDocList 搜索文档列表
     */
    private void initFarm(List<Farm> farmList, List<SearchDoc> searchDocList) {
        List<SearchDoc> docList = farmList.stream()
                .map(searchConverter::toDoc)
                .toList();
        searchDocList.addAll(docList);
    }

    /**
     * 初始化领养数据
     * @param farmMap 农场Map
     * @param searchDocList 搜索文档列表
     */
    private void initAdoption(Map<Long, Farm> farmMap, List<SearchDoc> searchDocList) {
        List<SearchDoc> docList = adoptionService.list()
                .stream()
                .map(searchConverter::toDoc)
                .filter(searchDoc -> extracted(searchDoc, farmMap))
                .toList();
        searchDocList.addAll(docList);
    }

    /**
     * 提取并设置农场相关信息
     * @param searchDoc 搜索文档
     * @param farmMap 农场Map
     * @return 是否成功提取
     */
    private boolean extracted(SearchDoc searchDoc,Map<Long, Farm> farmMap) {
        Farm farm = farmMap.get(searchDoc.getFarmId());

        if (farm == null){
            return false;
        }

        searchDoc.setAddress(farm.getName());
        searchDoc.setLat(farm.getLat());
        searchDoc.setLng(farm.getLng());

        return true;
    }
}
